#lang racket

(require "rename-mutable-pair-ops.rkt")

(provide make-deque empty-deque? rear-deque front-deque front-insert-deque! rear-insert-deque!
         front-delete-deque! rear-delete-deque! print-deque)

(define (front-ptr deque) (car deque))

(define (rear-ptr deque) (cdr deque))

(define (set-front-ptr! deque item) (set-car! deque item))

(define (set-rear-ptr! deque item) (set-cdr! deque item))

;ITEM FUNCTIONS----------------------------------------------------------------------------------

(define (make-item content) (list (cons '() '()) content))

(define (content item) (car (cdr item)))

(define (item-ahead item) (car (car item)))

(define (item-behind item) (cdr (car item)))

(define (set-item-ahead! item ahead-item)
  (set-car! (car item) ahead-item))

(define (set-item-behind! item behind-item)
  (set-cdr! (car item) behind-item))

;INTERFACE FUNCTIONS-----------------------------------------------------------------------------

(define (make-deque) (cons '() '()))

(define (empty-deque? deque) (and (null? (front-ptr deque))
                                  (null? (rear-ptr deque))))

(define (front-deque deque)
  (if (empty-deque? deque)
      (error "deque ist empty")
      (content (front-ptr deque))))

(define (rear-deque deque)
  (if (empty-deque? deque)
      (error "deque ist empty")
      (content (rear-ptr deque))))

(define (front-insert-deque! deque content)
  (let ((new-item (make-item content))
        (front-item (front-ptr deque)))
    (cond ((empty-deque? deque) (set-rear-ptr! deque new-item)
                                (set-front-ptr! deque new-item))
          (else (set-item-behind! new-item front-item)
                (set-item-ahead! front-item new-item)
                (set-front-ptr! deque new-item)))))

(define (rear-insert-deque! deque content)
  (let ((new-item (make-item content))
        (rear-item (rear-ptr deque)))
    (cond ((empty-deque? deque) (set-front-ptr! deque new-item)
                                (set-rear-ptr! deque new-item))
          (else (set-item-ahead! new-item rear-item)
                (set-item-behind! rear-item new-item)
                (set-rear-ptr! deque new-item)))))

;(define (front-delete-deque! deque)
;  (let ((front-item (front-ptr deque)))
;    (cond ((empty-deque? deque) (error "deque is empty"))
;          (else ;(set-front-ptr! deque (item-behind front-item))
;                ;(set-item-behind! front-item '())
;                (set-item-ahead! (item-behind front-item) '())
;                (set-front-ptr! deque (item-behind front-item))
;                (cond ((empty-deque? deque) (set-rear-ptr! deque '())))))))

(define (front-delete-deque! deque)
  (let ((front-item (front-ptr deque)))
    (cond ((empty-deque? deque)
           (error "deque is empty"))
          (else (let ((ff-item (item-behind front-item)))
                  (cond ((null? ff-item) (set-front-ptr! deque '())
                                         (set-rear-ptr! deque '()))
                        (else (set-item-ahead! ff-item '())
                              (set-front-ptr! deque ff-item))))))))

(define (rear-delete-deque! deque)
  (let ((rear-item (rear-ptr deque)))
    (cond ((empty-deque? deque)
           (error "deque is empty"))
          (else (let ((rr-item (item-ahead rear-item)))
                  (cond ((null? rr-item) (set-front-ptr! deque '())
                                         (set-rear-ptr! deque '()))
                        (else (set-item-behind! rr-item '())
                              (set-rear-ptr! deque rr-item))))))))

(define (print-deque deque)
  (define (iter item)
    (cond ((not (null? item))
           (display (content item))
           (cond ((not (null? (item-behind item))) (display " ")))
           (iter (item-behind item)))))
  (display "(")
  (iter (front-ptr deque))
  (display ")\n"))